In [ ]:
import numpy as np
from menpo.transform import Rotation, Scale, Translation
In [ ]:
rotation = np.array([[ 0.36, 0.48, -0.80],
[-0.80, 0.60, 0.00],
[ 0.48, 0.64, 0.60]])
scale = np.array([7,3, 15])
scale2 = np.ones(3)*-3.52
translation = np.array([-1,20])
In [ ]:
r = Rotation(rotation)
nus = Scale(scale) # NonUniformScale (Affine)
us = Scale(2, n_dims=3) # UniformScale (Similarity)
t = Translation(translation)
All affine transforms are printable. You will see the usual homogeneous matrix, and an English decription of what the affine transform does
In [ ]:
print r
In [ ]:
print nus
In [ ]:
print t
All these are instances of DiscreteAffineTransform
. That means we can ask any of these to invert themselves
In [ ]:
print us
print us.pseudoinverse
All affine transforms can be chained together using the chain(another_affine_transform)
method. This produces a new AffineTransform
. Note that printing a general affine transform describes an equalivilent set of discrete affine transforms (that is, a sequence of discrete Rotation
, Translation
and Scale
operations) that perform the same transform
In [ ]:
rotation_followed_by_scale = r.compose_before(nus)
print rotation_followed_by_scale
We can request this sequence directly by using the decompose()
method
notice how all affine transforms support eqality checking
In [ ]:
decomposed = rotation_followed_by_scale.decompose()
result_of_chain = reduce(lambda x, y: x.compose_before(y), decomposed)
print result_of_chain
print 'Does chaining the decomposition do the same as the original? %s' % (result_of_chain == rotation_followed_by_scale)
Note that chaining SimilarityTransform
objects together yields a SimilarityTransform
instead.
In [ ]:
print r.compose_before(us)
Finally, note that all instances of Transform
are guaranteed to have an .apply()
method. Novel points can be passed in here, which will then be transformed (the result is returned, and the points left as they are). However, objects passed into apply()
can define a ._transform()
method, signifing that this object knows how to handle it's own transformation. In this case, the trasformation is applied in place. PointCloud
is one such class that defines this method.
In [ ]:
%matplotlib inline
from menpo.shape import PointCloud
points = np.array([[0.0, 0.0],
[1.0, 0.0],
[1.0, 1.0],
[0.0, 1.0]])
pc = PointCloud(points)
print pc
print pc.points
pc.view()
A transform can .apply()
to some raw points to yield new ones...
In [ ]:
import matplotlib.pyplot as plt
new_points = t.apply(points)
print new_points
plt.scatter(new_points[:, 0], new_points[:, 1])
..or can apply directly to Transformable
objects.
In [ ]:
pc3 = t.apply(pc)
print pc3.points
pc3.view()